Set-up packages // libraries and prepare for data import:

## Uncomment install.packages and run outside of notebook environment: 
## install.packages(c("psych" ,"xtable", "tidyverse", "jsonlite", "likert", "ggplot2", "ploty", "mosaic", "modelr", "broom"))
library(psych)
library(likert)
Loading required package: ggplot2

Attaching package: ‘ggplot2’

The following objects are masked from ‘package:psych’:

    %+%, alpha

Loading required package: xtable
library(jsonlite)
library(ggplot2)
library(plotly)

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
library(modelr)

Attaching package: ‘modelr’

The following object is masked from ‘package:psych’:

    heights
library(broom)

Attaching package: ‘broom’

The following object is masked from ‘package:modelr’:

    bootstrap
source("http://pcwww.liv.ac.uk/~william/R/crosstab.r")
theme_set(theme_classic())

Set-up directories, import and clean data:

rm(list=ls())
setwd("/Users/allieblaising/desktop/bang/R") 
getwd()
[1] "/Users/allieblaising/Desktop/bang/R"
dataPath = "../.data"
## Define function to extract survey results: 
extractSurvey = function(frame,survey) {
  rounds = seq(1,length(frame$results.format[[1]]))
  roundResponses = lapply(rounds, function(round) {
    getCol = paste("results.",survey,".",round, sep="")
    surveyCols = Filter(function(x) grepl(getCol,x),names(frame))
    newCols = lapply(surveyCols, function(x) gsub(getCol,paste("results.",survey, sep=""),x) )
    surveyFrame = frame[,surveyCols]
    if (is.null(newCols)) {return("No newCols")}
    names(surveyFrame) = newCols
    surveyFrame$id = frame$id
    surveyFrame$round = round
    surveyFrame$batch = frame$batch
    surveyFrame$rooms = frame$rooms
    surveyFrame$manipulation = frame$results.manipulationCheck
    surveyFrame$blacklist = frame$results.blacklistCheck
    return(surveyFrame)
  })
  return(Reduce(rbind, roundResponses))
}
#Find directory for import (be sure to verify that batch #s align from bangData import and imports below): 
batches = dir(dataPath, pattern = "^[0-9]+$" )
completeBatches = Filter(function(batch) { 
  if (any(dir(paste(dataPath,batch,sep="/")) == "batch.json") && (any(dir(paste(dataPath,batch,sep="/")) == "users.json")) ) {
    batchData = read_json(paste(dataPath,batch,"batch.json",sep="/"), simplifyVector = TRUE)
    return(any(batchData$batchComplete == TRUE))
  } 
  return(FALSE)
}, batches)
userFiles = lapply(completeBatches, function(batch) {
  userFile = read_json(paste(dataPath,batch,"users.json",sep="/"), simplifyVector=TRUE)
  return(flatten(userFile, recursive = TRUE))
})
## Retroactively find rooms from chat data: 
overlappingFiles = Reduce(function(x,y) merge(x, y, all=TRUE), userFiles)
roundsWithRooms = apply(overlappingFiles,1,function(x) {
  roomsForIndividual = lapply(seq(1,3),function(y) {
    x$room = x$rooms[y]
    x$round = y
    return(x)
  })
  return(Reduce(rbind, roomsForIndividual))
})
library(tidyverse)
── Attaching packages ────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
✔ tibble  1.4.2     ✔ purrr   0.2.5
✔ tidyr   0.8.1     ✔ dplyr   0.7.6
✔ readr   1.1.1     ✔ stringr 1.3.1
✔ tibble  1.4.2     ✔ forcats 0.3.0
── Conflicts ───────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ ggplot2::%+%()     masks psych::%+%()
✖ ggplot2::alpha()   masks psych::alpha()
✖ broom::bootstrap() masks modelr::bootstrap()
✖ dplyr::filter()    masks plotly::filter(), stats::filter()
✖ purrr::flatten()   masks jsonlite::flatten()
✖ dplyr::lag()       masks stats::lag()
✖ dplyr::recode()    masks likert::recode()
library(mosaic)
Loading required package: lattice
Loading required package: ggformula

New to ggformula?  Try the tutorials: 
    learnr::run_tutorial("introduction", package = "ggformula")
    learnr::run_tutorial("refining", package = "ggformula")

Attaching package: ‘ggformula’

The following object is masked from ‘package:modelr’:

    na.warn

Loading required package: mosaicData
Loading required package: Matrix

Attaching package: ‘Matrix’

The following object is masked from ‘package:tidyr’:

    expand


The 'mosaic' package masks several functions from core packages in order to add 
additional features.  The original behavior of these functions should not be affected by this.

Note: If you use the Matrix package, be sure to load it BEFORE loading mosaic.

Attaching package: ‘mosaic’

The following object is masked from ‘package:Matrix’:

    mean

The following objects are masked from ‘package:dplyr’:

    count, do, tally

The following object is masked from ‘package:purrr’:

    cross

The following object is masked from ‘package:modelr’:

    resample

The following object is masked from ‘package:plotly’:

    do

The following object is masked from ‘package:ggplot2’:

    stat

The following objects are masked from ‘package:psych’:

    logit, read.file, rescale

The following objects are masked from ‘package:stats’:

    binom.test, cor, cor.test, cov, fivenum, IQR, median, prop.test, quantile, sd, t.test, var

The following objects are masked from ‘package:base’:

    max, mean, min, prod, range, sample, sum
## To filter the right batch numbers, add the first batch number for our runs (i.e. batch >= "first batch #") 
## overlappingFiles <- overlappingFiles %>% filter(batch=="1536132233074")

More cleaning before visualizations:

## Apply extract survey function to extract the right columns and rows for viability survey: 
# overlappingFiles <- overlappingFiles %>% filter(batch>="1536276904547") 
# qFifteen <- as.data.frame(extractSurvey(overlappingFiles, 'qFifteenCheck'))
# qSixteen <- as.data.frame(extractSurvey(overlappingFiles, 'qSixteenCheck'))
# viabilitySurvey <- as.data.frame(extractSurvey(overlappingFiles, 'viabilityCheck'))  
# qFifteen <- qFifteen %>% select(id, results.qFifteenCheck)
# qSixteen <- qSixteen %>% select(id, results.qSixteenCheck) 
# qFifteen$id <-  unlist(qFifteen$id)
# qSixteen$id <-  unlist(qSixteen$id)
# postSurveyQs <- cbind(qFifteen, qSixteen) 
# frame <- cbind(viabilitySurvey, postSurveyQs)  
# frame <- frame[, !duplicated(colnames(frame))]
frame <- extractSurvey(overlappingFiles, 'viabilityCheck')
## Reduce to vertically combine rows in roundwithRooms list:  
finalRounds = as.data.frame(Reduce(rbind,roundsWithRooms))
## Subset incomplete cases from viability survey dataframe, use manipulation check b/c required for complete observation: 
data <- frame[frame$manipulation!="",]
## Rename room to rooms so that both are retained in future merge: 
data <- rename(data, rooms = "rooms")
## Subset incomplete cases for final rounds dataframe: 
data2 <- finalRounds[finalRounds$results.manipulationCheck!="", ]
## Select only variables of interest from final rounds: 
data2 = data2 %>% select(id, batch, room, bonus, name, friends, 
                         friends_history, results.condition, results.format,
                  results.manipulation,results.manipulationCheck,results.blacklistCheck, round)
## Convert to compatible data types before merge (**this should be simplified**)
data2$batch <- unlist(data2$batch)
data2$round <- unlist(data2$round)
data2$id <- unlist(data2$id) 
data$batch <- unlist(data$batch)
## Before merge, data and data2 should have the same # of observations
## Merge columns by id, round and batch #s: 
data <- left_join(data, data2, by=NULL)
Joining, by = c("id", "round", "batch")
## Subset only observations with batch #s in complete batches 
allConditions <- data[data$batch %in% completeBatches, ]

Conditionally assign conditions based on treatment and results column:

## Messy, but robust? Verify, verify, verify people:   
data <- data %>% mutate(
  condition = case_when(
    results.condition=='treatment' & results.format=="c(1, 2, 1)" & round==1 ~ "A", 
    results.condition=='treatment' & results.format=="c(1, 2, 1)" & round==2 ~ "B", 
    results.condition=='treatment' & results.format=="c(1, 2, 1)" & round==3 ~ "Ap", 
    results.condition=='treatment' & results.format=="c(1, 1, 2)" & round==1 ~ "A", 
    results.condition=='treatment' & results.format=="c(1, 1, 2)" & round==2 ~ "Ap", 
    results.condition=='treatment' & results.format=="c(1, 1, 2)" & round==3 ~ "B", 
    results.condition=='treatment' & results.format=="c(2, 1, 1)" & round==1 ~ "B", 
    results.condition=='treatment' & results.format=="c(2, 1, 1)" & round==2 ~ "A", 
    results.condition=='treatment' & results.format=="c(2, 1, 1)" & round==3 ~ "Ap" ,
    results.condition=='control' & results.format=="c(1, 2, 1)" & round==1 ~ "A", 
    results.condition=='control' & results.format=="c(1, 2, 1)" & round==2 ~ "B", 
    results.condition=='control' & results.format=="c(1, 2, 1)" & round==3 ~ "Ap", 
    results.condition=='control' & results.format=="c(1, 1, 2)" & round==1 ~ "A", 
    results.condition=='control' & results.format=="c(1, 1, 2)" & round==2 ~ "Ap", 
    results.condition=='control' & results.format=="c(1, 1, 2)" & round==3 ~ "B", 
    results.condition=='control' & results.format=="c(2, 1, 1)" & round==1 ~ "B", 
    results.condition=='control' & results.format=="c(2, 1, 1)" & round==2 ~ "A", 
    results.condition=='control' & results.format=="c(2, 1, 1)" & round==3 ~ "Ap" ,
    results.condition=='baseline' & results.format=="1:3" & round==1 ~ "A" ,
    results.condition=='baseline' & results.format=="1:3" & round==2 ~ "B" ,
    results.condition=='baseline' & results.format=="1:3" & round==3 ~ "C" 
  )) 

Set-up for factors for viability questions:

data <- rename(data, "repeatTeam" = results.viabilityCheck.15)
## Remove observations where viability survey wasn't on (remove this line if we want to keep observations with viability off): 
data <- na.omit(data)
## Factor for visualizations: 
levels <- c("Strongly Disagree", "Disagree", "Neutral","Agree", "Strongly Agree") 
clean <- data %>% 
  mutate_at(.vars = vars(contains("results.viabilityCheck")), funs(factor(., levels = levels))) 
## Create a new dataframe that converts factors to numeric for statistical analyses:
stats <- clean %>% mutate_if(is.factor, as.numeric)
for (i in 1:nrow(stats)) {
  stats$sum[i] <- sum(stats[i,1:14])                          
} 
stats$median <- median(stats$sum)
stats$mean <- mean(stats$sum)
## Revalue repeat team: keep plyr b/c some weird R stuff requires library to be called directly (recode values to )
stats$repeatTeam <- plyr::revalue(stats$repeatTeam, c("Yes"="0", "No"="1"))
stats$repeatTeam <- plyr::revalue(stats$repeatTeam, c("Keep this team"="0", "Do not keep this team"="1"))
## Convert to compatible classes for team grouping: 
stats$repeatTeam <- as.numeric(stats$repeatTeam)
stats$results.condition <- unlist(stats$results.condition)
stats$results.format <- as.character(stats$results.format)
stats$room <- unlist(stats$room)
## Dplyr to group teams and summarise variables for each group: group_by to find teams and summarise to compact individual results into group level results (i.e. one row of variable results per team)
groupedProportion <- stats %>%
  group_by(room, batch, round, condition, results.condition, results.format) %>%  ## to-do: add group ID in storage db. 
  summarise(n=n(), mean=mean(sum), median=median(sum),prop=sum(repeatTeam)/n, groupID=runif(1,0,2)) %>% 
## Filter out all teams with n=1 (i.e. a person in a one person team) 
  filter(n==2)
## Individual proportion: 
individualProportion <- stats %>% group_by(round, batch, room) %>% 
  mutate(sum=sum, mean=mean(sum), median=median(sum), n=n(),prop=sum(repeatTeam)/n) %>% 
  filter(n>1)
## Table showing how many teams we've run in each condition combination:  
print(table(groupedProportion$condition, groupedProportion$results.condition)) 
    
     baseline control treatment
  A        26      10        25
  Ap        0      10        25
  B        20      14        22
  C        29       0         0

Probability of fracture across teams and condition combinations:

  left_join(baselineFracture1, baselineFracture2, by=NULL, drop=TRUE)
Joining, by = c("room", "batch", "round", "condition", "results.condition", "results.format", "n", "mean", "median", "prop", "groupID", "fracture")

Section #1: Does fracture have continuity with prior measures?

1A: Report the % of correct guesses on the manipulation check:

## Treatment manipulation: 
treatmentManipulation <- cleanManipulation %>% group_by(id, results.condition, manipulationAnswers, manipulationAnswerKey) %>% filter(results.condition=="treatment") %>% 
  summarise(n=n()) 
## If user manipulation answers == manipulation answer key then add 1 
treatmentManipulation$correctAnswers <- sum(ifelse(treatmentManipulation$manipulationAnswers==treatmentManipulation$manipulationAnswerKey,1,0))
## Calculate percent of correct manipulation answers for treatment: 
treatmentManipulation <- treatmentManipulation %>% mutate(percentCorrect = (correctAnswers/(nrow(treatmentManipulation))))
## Control manipulation: 
controlManipulation <- cleanManipulation %>% group_by(id, results.condition, manipulationAnswers, manipulationAnswerKey) %>% filter(results.condition=="control") %>% 
  summarise(n=n()) 
## If user manipulation answers == manipulation answer key then add 1 
controlManipulation$correctAnswers <- sum(ifelse(controlManipulation$manipulationAnswers==controlManipulation$manipulationAnswerKey,1,0))
## Calculate percent of correct manipulation answers for control: 
controlManipulation <- controlManipulation %>% mutate(percentCorrect = (correctAnswers/(nrow(controlManipulation))))
## Proportion test comparing treatment manipulation percent correct with chance: 

1B: Proportion test comparing treatment manipulation percent correct with chance:

## ⅓ ~ 33% = chance, ~43 = treatment (FILL-IN EACH TIME YOU RUN WITH NEW DATA!)
propManipulation <- prop.test(x = c(33, 43), n = c(100, 100))
print(propManipulation)

    2-sample test for equality of proportions with continuity correction

data:  c(33, 43) out of c(100, 100)
X-squared = 1.719, df = 1, p-value = 0.1898
alternative hypothesis: two.sided
95 percent confidence interval:
 -0.24382407  0.04382407
sample estimates:
prop 1 prop 2 
  0.33   0.43 

1C: Logistic regression predicting binary fracture outcome from viability scales:

## Split data into 60% training and 40% testing data sets to test how well the model performs 
set.seed(123)
groupedProportionFracture$fracture <- as.numeric(groupedProportionFracture$fracture) 
sample <- sample(c(TRUE, FALSE), nrow(groupedProportionFracture), replace = T, prob = c(0.6,0.4))
train <- groupedProportionFracture[sample, ]
test <- groupedProportionFracture[!sample, ]
## Simple logistic regression: we will fit a logistic regression model in order to predict 
## the probability of fracture based on a team's average viability sum: 
model1 <- glm(fracture ~ mean, family = "binomial", data = train)
summary(model1)

Call:
glm(formula = fracture ~ mean, family = "binomial", data = train)

Deviance Residuals: 
     Min        1Q    Median        3Q       Max  
-1.94811  -0.46471   0.04798   0.38542   2.43161  

Coefficients:
            Estimate Std. Error z value Pr(>|z|)    
(Intercept) 13.79411    2.58357   5.339 9.34e-08 ***
mean        -0.26503    0.04908  -5.400 6.68e-08 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 152.165  on 109  degrees of freedom
Residual deviance:  71.765  on 108  degrees of freedom
AIC: 75.765

Number of Fisher Scoring iterations: 6
## To assess the linear regression deviance, look at deviance in summary output, if 
## deviance == sum of sqaures in linear regression, null deviance == difference between 
## a model with only the intercept ("no mean predictors") and the a saturated model 
## a model with a theoretically perfect fit. Model deviance (residual deviance) should be lower 
## small values == better fit. 
tidy(model1)
## Coefficient estimtes from log regression characterize relationship between the predictor and 
## response variable on a log-odds scale, so binary increase from no fracture - fracture can be interpreted as associated with a decrease in mean viability sum. 
## More coefficient output: measure the confidence intervals and accuracy of the coefficent: 
confint(model1)
Waiting for profiling to be done...
                 2.5 %     97.5 %
(Intercept)  9.3617399 19.6211689
mean        -0.3757527 -0.1807974
## Making predictions: 
## What is the probability of fracture given the following team mean viability scores: for example purposes: 40 and 65: 
predict(model1, data.frame(mean = c(50, 65)), type = "response")
         1          2 
0.63238720 0.03127928 
## From the output, we can see that the probability of fracture decreases by ~40% when mean viability sum increases from 40 to 65. 
## Model evaluation & diagnostics: 
## How well does the model fit the data? And how accurate are the predictions on an out-of-sample data set?
## Residul assessment: 
model1_data <- augment(model1) %>% 
  mutate(index = 1:n())
ggplot(model1_data, aes(index, .std.resid, color = mean)) + 
  geom_point(alpha = .5) +
  geom_ref_line(h = 3)

## Validation of predicted values: 
## How well does the model perform when predicting the target variable on out-of-sample observations? 
test.predicted.m1 <- predict(model1, newdata = test, type = "response")
## Classification performance for each model on the test data. Output gives us a list of true / false positives: 
list(
  model1 = table(test$mean, test.predicted.m1 > 0.5) %>% prop.table() %>% round(3)) 
$model1
      
       FALSE  TRUE
  32   0.000 0.014
  32.5 0.000 0.014
  36   0.000 0.028
  36.5 0.000 0.014
  37   0.000 0.014
  41.5 0.000 0.028
  44   0.000 0.014
  45   0.000 0.014
  46.5 0.000 0.028
  47   0.000 0.014
  48.5 0.000 0.042
  49   0.000 0.028
  49.5 0.000 0.014
  50   0.000 0.028
  50.5 0.000 0.014
  52   0.000 0.028
  52.5 0.014 0.000
  53   0.028 0.000
  54   0.028 0.000
  54.5 0.014 0.000
  55.5 0.028 0.000
  56   0.099 0.000
  56.5 0.014 0.000
  57   0.028 0.000
  58   0.028 0.000
  58.5 0.042 0.000
  59   0.014 0.000
  59.5 0.014 0.000
  60   0.014 0.000
  60.5 0.014 0.000
  61   0.014 0.000
  61.5 0.028 0.000
  62   0.028 0.000
  62.5 0.014 0.000
  63   0.056 0.000
  64   0.014 0.000
  65   0.014 0.000
  66   0.014 0.000
  66.5 0.014 0.000
  69   0.014 0.000
  70   0.070 0.000
table(test$mean, test.predicted.m1 > 0.5)
      
       FALSE TRUE
  32       0    1
  32.5     0    1
  36       0    2
  36.5     0    1
  37       0    1
  41.5     0    2
  44       0    1
  45       0    1
  46.5     0    2
  47       0    1
  48.5     0    3
  49       0    2
  49.5     0    1
  50       0    2
  50.5     0    1
  52       0    2
  52.5     1    0
  53       2    0
  54       2    0
  54.5     1    0
  55.5     2    0
  56       7    0
  56.5     1    0
  57       2    0
  58       2    0
  58.5     3    0
  59       1    0
  59.5     1    0
  60       1    0
  60.5     1    0
  61       1    0
  61.5     2    0
  62       2    0
  62.5     1    0
  63       4    0
  64       1    0
  65       1    0
  66       1    0
  66.5     1    0
  69       1    0
  70       5    0

1D: Graph of fracture/no fracture vs. mean/stdev viability scale

## Overall: 
g <- ggplot(groupedProportionFracture, aes(factor(fracture), mean)) 
g + geom_boxplot(varwidth=T, fill="plum") + 
  labs(subtitle="Team fracture value vs. mean viability score: fracture >=0.50 across all conditions (n=2)", 
       x="",
       y="Numeric sum of viability measures questions (range: 7-70)") 

## By condition + format: 
g <- ggplot(groupedProportionFracture, aes(factor(fracture), mean)) 
g + geom_boxplot(varwidth=T, fill="plum") + 
  labs(subtitle="Team fracture value vs. mean viability score: fracture >=0.50 (n=2)", 
       x="",
       y="Numeric sum of viability measures questions (range: 7-70)") + facet_grid(condition ~ results.condition) 

ggplot(data=groupedProportionFracture, aes(fracture, mean)) + 
   geom_point() +
  stat_smooth(method = "lm", col = "red") + labs(main="Scatterplot of fracture value vs. mean for team viability sums across all conditions (n=2)") +  facet_grid(condition ~ results.condition) 

ggplot(data=groupedProportionFracture, aes(fracture, mean)) + 
   geom_point() +
  stat_smooth(method = "lm", col = "red") + labs(main="Scatterplot of fracture value vs. mean for team viability sums (n=2)") +  facet_grid(condition ~ results.condition) 

Section #2: How often does fracture occur?

2A: P(binary fracture) histogram of fracture proportion (by team)

## First make sure you've made ABC condition
ggplot(data=groupedProportion, aes(groupedProportion$prop)) + 
  geom_histogram(breaks=seq(0, 1, by=0.20), 
                 col="red", 
                 fill="green", 
                 alpha=.2) + labs(title="Frequency of team fracture proportions by condition and pattern sequence", 
                                  x="team fracture proportion", y="Count") + facet_grid(results.condition ~ .) 

library(MASS)     

Attaching package: ‘MASS’

The following object is masked from ‘package:dplyr’:

    select

The following object is masked from ‘package:plotly’:

    select
## Test if whether fracture smoking habit is independent of condition at .05 significance level: 
chi = table(groupedProportionFracture$fracture, groupedProportionFracture$results.condition)  
chi
   
    baseline control treatment
  0       41      18        38
  1       34      16        34
print(chisq.test(chi)) 

    Pearson's Chi-squared test

data:  chi
X-squared = 0.059809, df = 2, p-value = 0.9705

2B: What’s the overall % of fracturing the second time? (by condition)

## Filtering second time only: 
groupedProportionFracture$fracture <- as.numeric(groupedProportionFracture$fracture)
## TO-DO: review below code, worried it's incorrect: 
groupedProportionFractureSecond <- groupedProportionFracture %>% group_by(results.condition) %>% 
      filter(condition=="Ap") %>% 
      mutate(overallPercent = sum(as.numeric(fracture))) %>% 
      summarise(n=n(), overallPercent=unique(overallPercent)/n) 
print(groupedProportionFractureSecond)
## For baseline theoretical distribution: (to-do: look over this, worried also that it's wrong)
groupedProportionFractureSecondBase <- groupedProportionFractureBaseline %>% 
      filter(round=="3") %>% 
      summarise(n=n(), overallPercent=sum(as.numeric(fracture))/n) 
print(mean(groupedProportionFractureSecondBase$overallPercent))
[1] 0.4930556
## Set-up separate groups for proportion tests to answer: does unmasked fracture more/less than masked 
## and more/less than new pairs? 
## Control: 
## Proportion tests for each (TO-DO, figure out argument stuff: this doesn't seem like the right test to run for the question we're asking?) also, fill-this in every time you get new data: 
## Is the proportion of fracture in the second round significantly different in the two conditions (i.e. treatment + baseline) 
treatmentvsBaselineChange <- c(48, 49)
propFractureChangeTreatmentvsBase <- prop.test(x = c(treatmentvsBaselineChange), n = c(100, 100))
print(propFractureChangeTreatmentvsBase) 

    2-sample test for equality of proportions with continuity correction

data:  c(treatmentvsBaselineChange) out of c(100, 100)
X-squared = 0, df = 1, p-value = 1
alternative hypothesis: two.sided
95 percent confidence interval:
 -0.1585211  0.1385211
sample estimates:
prop 1 prop 2 
  0.48   0.49 
## Is the proportion of fracture in the second round significantly different in the two conditions (i.e. control + baseline) 
controlvsBaselineChange <- c(40, 49)
propFractureChangeControlvsBase <- prop.test(x = c(controlvsBaselineChange), n = c(100, 100))
print(propFractureChangeControlvsBase)

    2-sample test for equality of proportions with continuity correction

data:  c(controlvsBaselineChange) out of c(100, 100)
X-squared = 1.2957, df = 1, p-value = 0.255
alternative hypothesis: two.sided
95 percent confidence interval:
 -0.23718348  0.05718348
sample estimates:
prop 1 prop 2 
  0.40   0.49 

Section 3: How consistent is fracture?

3A: calculating the conditional probabilities of fracture for each condition:

controlFracture12 <- sum(ifelse(controlFracture1$fracture=="1" & controlFracture2$fracture=="1",1,0))/nrow(controlFracture)
# of groups who fractured only 1
controlFractureOnly1 <- sum(ifelse(controlFracture1$fracture=="1" & controlFracture2$fracture=="0",1,0))/nrow(controlFracture) 
# of groups who fractured only 2
controlFractureOnly2 <- sum(ifelse(controlFracture1$fracture=="0" & controlFracture2$fracture=="1",1,0))/nrow(controlFracture)
# of groups who fractured never        
controlFractureNever <- sum(ifelse(controlFracture1$fracture=="0" & controlFracture2$fracture=="0",1,0))/nrow(controlFracture)
conditionalProbControl <- matrix(c(controlFracture12, controlFractureOnly1, controlFractureOnly2, controlFractureNever),ncol=2,byrow=TRUE)
colnames(conditionalProbControl) <- c("Ap frac","Ap no frac") 
rownames(conditionalProbTreatment) <- c("A frac","A no frac")
conditionalProbControl <- as.table(conditionalProbControl)
conditionalProbControl
  Ap frac Ap no frac
A     0.3        0.0
B     0.1        0.6

3B: Now investigating the big result: switch %: what’s the % of pairs flipping their decisions?

controlFractureAbsSum <- sum(controlFracture$absFracture)
print(controlFractureAbsSum)
[1] 1

Visualizing change:

LS0tCnRpdGxlOiAiQXNwbG9kZSB0ZXN0IG91dGxpbmUiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIFNldC11cCBwYWNrYWdlcyAvLyBsaWJyYXJpZXMgYW5kIHByZXBhcmUgZm9yIGRhdGEgaW1wb3J0OiAKYGBge3J9CiMjIFVuY29tbWVudCBpbnN0YWxsLnBhY2thZ2VzIGFuZCBydW4gb3V0c2lkZSBvZiBub3RlYm9vayBlbnZpcm9ubWVudDogCiMjIGluc3RhbGwucGFja2FnZXMoYygicHN5Y2giICwieHRhYmxlIiwgInRpZHl2ZXJzZSIsICJqc29ubGl0ZSIsICJsaWtlcnQiLCAiZ2dwbG90MiIsICJwbG90eSIsICJtb3NhaWMiLCAibW9kZWxyIiwgImJyb29tIikpCgpsaWJyYXJ5KHBzeWNoKQpsaWJyYXJ5KGxpa2VydCkKbGlicmFyeShqc29ubGl0ZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShtb2RlbHIpCmxpYnJhcnkoYnJvb20pCnNvdXJjZSgiaHR0cDovL3Bjd3d3Lmxpdi5hYy51ay9+d2lsbGlhbS9SL2Nyb3NzdGFiLnIiKQp0aGVtZV9zZXQodGhlbWVfY2xhc3NpYygpKQpgYGAKCiMjIFNldC11cCBkaXJlY3RvcmllcywgaW1wb3J0IGFuZCBjbGVhbiBkYXRhOiAKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIi9Vc2Vycy9hbGxpZWJsYWlzaW5nL2Rlc2t0b3AvYmFuZy9SIikgCmdldHdkKCkKZGF0YVBhdGggPSAiLi4vLmRhdGEiCiMjIERlZmluZSBmdW5jdGlvbiB0byBleHRyYWN0IHN1cnZleSByZXN1bHRzOiAKZXh0cmFjdFN1cnZleSA9IGZ1bmN0aW9uKGZyYW1lLHN1cnZleSkgewogIHJvdW5kcyA9IHNlcSgxLGxlbmd0aChmcmFtZSRyZXN1bHRzLmZvcm1hdFtbMV1dKSkKICByb3VuZFJlc3BvbnNlcyA9IGxhcHBseShyb3VuZHMsIGZ1bmN0aW9uKHJvdW5kKSB7CiAgICBnZXRDb2wgPSBwYXN0ZSgicmVzdWx0cy4iLHN1cnZleSwiLiIscm91bmQsIHNlcD0iIikKICAgIHN1cnZleUNvbHMgPSBGaWx0ZXIoZnVuY3Rpb24oeCkgZ3JlcGwoZ2V0Q29sLHgpLG5hbWVzKGZyYW1lKSkKICAgIG5ld0NvbHMgPSBsYXBwbHkoc3VydmV5Q29scywgZnVuY3Rpb24oeCkgZ3N1YihnZXRDb2wscGFzdGUoInJlc3VsdHMuIixzdXJ2ZXksIHNlcD0iIikseCkgKQogICAgc3VydmV5RnJhbWUgPSBmcmFtZVssc3VydmV5Q29sc10KICAgIGlmIChpcy5udWxsKG5ld0NvbHMpKSB7cmV0dXJuKCJObyBuZXdDb2xzIil9CiAgICBuYW1lcyhzdXJ2ZXlGcmFtZSkgPSBuZXdDb2xzCiAgICBzdXJ2ZXlGcmFtZSRpZCA9IGZyYW1lJGlkCiAgICBzdXJ2ZXlGcmFtZSRyb3VuZCA9IHJvdW5kCiAgICBzdXJ2ZXlGcmFtZSRiYXRjaCA9IGZyYW1lJGJhdGNoCiAgICBzdXJ2ZXlGcmFtZSRyb29tcyA9IGZyYW1lJHJvb21zCiAgICBzdXJ2ZXlGcmFtZSRtYW5pcHVsYXRpb24gPSBmcmFtZSRyZXN1bHRzLm1hbmlwdWxhdGlvbkNoZWNrCiAgICBzdXJ2ZXlGcmFtZSRibGFja2xpc3QgPSBmcmFtZSRyZXN1bHRzLmJsYWNrbGlzdENoZWNrCiAgICByZXR1cm4oc3VydmV5RnJhbWUpCiAgfSkKICByZXR1cm4oUmVkdWNlKHJiaW5kLCByb3VuZFJlc3BvbnNlcykpCn0KI0ZpbmQgZGlyZWN0b3J5IGZvciBpbXBvcnQgKGJlIHN1cmUgdG8gdmVyaWZ5IHRoYXQgYmF0Y2ggI3MgYWxpZ24gZnJvbSBiYW5nRGF0YSBpbXBvcnQgYW5kIGltcG9ydHMgYmVsb3cpOiAKYmF0Y2hlcyA9IGRpcihkYXRhUGF0aCwgcGF0dGVybiA9ICJeWzAtOV0rJCIgKQpjb21wbGV0ZUJhdGNoZXMgPSBGaWx0ZXIoZnVuY3Rpb24oYmF0Y2gpIHsgCiAgaWYgKGFueShkaXIocGFzdGUoZGF0YVBhdGgsYmF0Y2gsc2VwPSIvIikpID09ICJiYXRjaC5qc29uIikgJiYgKGFueShkaXIocGFzdGUoZGF0YVBhdGgsYmF0Y2gsc2VwPSIvIikpID09ICJ1c2Vycy5qc29uIikpICkgewogICAgYmF0Y2hEYXRhID0gcmVhZF9qc29uKHBhc3RlKGRhdGFQYXRoLGJhdGNoLCJiYXRjaC5qc29uIixzZXA9Ii8iKSwgc2ltcGxpZnlWZWN0b3IgPSBUUlVFKQogICAgcmV0dXJuKGFueShiYXRjaERhdGEkYmF0Y2hDb21wbGV0ZSA9PSBUUlVFKSkKICB9IAogIHJldHVybihGQUxTRSkKfSwgYmF0Y2hlcykKdXNlckZpbGVzID0gbGFwcGx5KGNvbXBsZXRlQmF0Y2hlcywgZnVuY3Rpb24oYmF0Y2gpIHsKICB1c2VyRmlsZSA9IHJlYWRfanNvbihwYXN0ZShkYXRhUGF0aCxiYXRjaCwidXNlcnMuanNvbiIsc2VwPSIvIiksIHNpbXBsaWZ5VmVjdG9yPVRSVUUpCiAgcmV0dXJuKGZsYXR0ZW4odXNlckZpbGUsIHJlY3Vyc2l2ZSA9IFRSVUUpKQp9KQoKIyMgUmV0cm9hY3RpdmVseSBmaW5kIHJvb21zIGZyb20gY2hhdCBkYXRhOiAKb3ZlcmxhcHBpbmdGaWxlcyA9IFJlZHVjZShmdW5jdGlvbih4LHkpIG1lcmdlKHgsIHksIGFsbD1UUlVFKSwgdXNlckZpbGVzKQpyb3VuZHNXaXRoUm9vbXMgPSBhcHBseShvdmVybGFwcGluZ0ZpbGVzLDEsZnVuY3Rpb24oeCkgewogIHJvb21zRm9ySW5kaXZpZHVhbCA9IGxhcHBseShzZXEoMSwzKSxmdW5jdGlvbih5KSB7CiAgICB4JHJvb20gPSB4JHJvb21zW3ldCiAgICB4JHJvdW5kID0geQogICAgcmV0dXJuKHgpCiAgfSkKICByZXR1cm4oUmVkdWNlKHJiaW5kLCByb29tc0ZvckluZGl2aWR1YWwpKQp9KQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtb3NhaWMpCgojIyBUbyBmaWx0ZXIgdGhlIHJpZ2h0IGJhdGNoIG51bWJlcnMsIGFkZCB0aGUgZmlyc3QgYmF0Y2ggbnVtYmVyIGZvciBvdXIgcnVucyAoaS5lLiBiYXRjaCA+PSAiZmlyc3QgYmF0Y2ggIyIpICAKIyMgb3ZlcmxhcHBpbmdGaWxlcyA8LSBvdmVybGFwcGluZ0ZpbGVzICU+JSBmaWx0ZXIoYmF0Y2g9PSIxNTM2MTMyMjMzMDc0IikKCmBgYAoKIyMgTW9yZSBjbGVhbmluZyBiZWZvcmUgdmlzdWFsaXphdGlvbnM6IApgYGB7cn0KIyMgRm9yIHdoZW4gd2Ugc3RhcnQgaW5wdXR0aW5nIG5ldyBiYXRjaGVzIG9ubHk6IAojIG92ZXJsYXBwaW5nRmlsZXMgPC0gb3ZlcmxhcHBpbmdGaWxlcyAlPiUgZmlsdGVyKGJhdGNoPj0iMTUzNjI3NjkwNDU0NyIpIAojIHFGaWZ0ZWVuIDwtIGFzLmRhdGEuZnJhbWUoZXh0cmFjdFN1cnZleShvdmVybGFwcGluZ0ZpbGVzLCAncUZpZnRlZW5DaGVjaycpKQojIHFTaXh0ZWVuIDwtIGFzLmRhdGEuZnJhbWUoZXh0cmFjdFN1cnZleShvdmVybGFwcGluZ0ZpbGVzLCAncVNpeHRlZW5DaGVjaycpKQojIHZpYWJpbGl0eVN1cnZleSA8LSBhcy5kYXRhLmZyYW1lKGV4dHJhY3RTdXJ2ZXkob3ZlcmxhcHBpbmdGaWxlcywgJ3ZpYWJpbGl0eUNoZWNrJykpICAKIyBxRmlmdGVlbiA8LSBxRmlmdGVlbiAlPiUgc2VsZWN0KGlkLCByZXN1bHRzLnFGaWZ0ZWVuQ2hlY2spCiMgcVNpeHRlZW4gPC0gcVNpeHRlZW4gJT4lIHNlbGVjdChpZCwgcmVzdWx0cy5xU2l4dGVlbkNoZWNrKSAKIyBxRmlmdGVlbiRpZCA8LSAgdW5saXN0KHFGaWZ0ZWVuJGlkKQojIHFTaXh0ZWVuJGlkIDwtICB1bmxpc3QocVNpeHRlZW4kaWQpCiMgcG9zdFN1cnZleVFzIDwtIGNiaW5kKHFGaWZ0ZWVuLCBxU2l4dGVlbikgCiMgZnJhbWUgPC0gY2JpbmQodmlhYmlsaXR5U3VydmV5LCBwb3N0U3VydmV5UXMpICAKIyBmcmFtZSA8LSBmcmFtZVssICFkdXBsaWNhdGVkKGNvbG5hbWVzKGZyYW1lKSldCgpmcmFtZSA8LSBleHRyYWN0U3VydmV5KG92ZXJsYXBwaW5nRmlsZXMsICd2aWFiaWxpdHlDaGVjaycpCiMjIFJlZHVjZSB0byB2ZXJ0aWNhbGx5IGNvbWJpbmUgcm93cyBpbiByb3VuZHdpdGhSb29tcyBsaXN0OiAgCmZpbmFsUm91bmRzID0gYXMuZGF0YS5mcmFtZShSZWR1Y2UocmJpbmQscm91bmRzV2l0aFJvb21zKSkKIyMgU3Vic2V0IGluY29tcGxldGUgY2FzZXMgZnJvbSB2aWFiaWxpdHkgc3VydmV5IGRhdGFmcmFtZSwgdXNlIG1hbmlwdWxhdGlvbiBjaGVjayBiL2MgcmVxdWlyZWQgZm9yIGNvbXBsZXRlIG9ic2VydmF0aW9uOiAKZGF0YSA8LSBmcmFtZVtmcmFtZSRtYW5pcHVsYXRpb24hPSIiLF0KIyMgUmVuYW1lIHJvb20gdG8gcm9vbXMgc28gdGhhdCBib3RoIGFyZSByZXRhaW5lZCBpbiBmdXR1cmUgbWVyZ2U6IApkYXRhIDwtIHJlbmFtZShkYXRhLCByb29tcyA9ICJyb29tcyIpCiMjIFN1YnNldCBpbmNvbXBsZXRlIGNhc2VzIGZvciBmaW5hbCByb3VuZHMgZGF0YWZyYW1lOiAKZGF0YTIgPC0gZmluYWxSb3VuZHNbZmluYWxSb3VuZHMkcmVzdWx0cy5tYW5pcHVsYXRpb25DaGVjayE9IiIsIF0KIyMgU2VsZWN0IG9ubHkgdmFyaWFibGVzIG9mIGludGVyZXN0IGZyb20gZmluYWwgcm91bmRzOiAKZGF0YTIgPSBkYXRhMiAlPiUgc2VsZWN0KGlkLCBiYXRjaCwgcm9vbSwgYm9udXMsIG5hbWUsIGZyaWVuZHMsIAogICAgICAgICAgICAgICAgICAgICAgICAgZnJpZW5kc19oaXN0b3J5LCByZXN1bHRzLmNvbmRpdGlvbiwgcmVzdWx0cy5mb3JtYXQsCiAgICAgICAgICAgICAgICAgIHJlc3VsdHMubWFuaXB1bGF0aW9uLHJlc3VsdHMubWFuaXB1bGF0aW9uQ2hlY2sscmVzdWx0cy5ibGFja2xpc3RDaGVjaywgcm91bmQpCiMjIENvbnZlcnQgdG8gY29tcGF0aWJsZSBkYXRhIHR5cGVzIGJlZm9yZSBtZXJnZSAoKip0aGlzIHNob3VsZCBiZSBzaW1wbGlmaWVkKiopCmRhdGEyJGJhdGNoIDwtIHVubGlzdChkYXRhMiRiYXRjaCkKZGF0YTIkcm91bmQgPC0gdW5saXN0KGRhdGEyJHJvdW5kKQpkYXRhMiRpZCA8LSB1bmxpc3QoZGF0YTIkaWQpIApkYXRhJGJhdGNoIDwtIHVubGlzdChkYXRhJGJhdGNoKQoKIyMgQmVmb3JlIG1lcmdlLCBkYXRhIGFuZCBkYXRhMiBzaG91bGQgaGF2ZSB0aGUgc2FtZSAjIG9mIG9ic2VydmF0aW9ucwojIyBNZXJnZSBjb2x1bW5zIGJ5IGlkLCByb3VuZCBhbmQgYmF0Y2ggI3M6IApkYXRhIDwtIGxlZnRfam9pbihkYXRhLCBkYXRhMiwgYnk9TlVMTCkKIyMgU3Vic2V0IG9ubHkgb2JzZXJ2YXRpb25zIHdpdGggYmF0Y2ggI3MgaW4gY29tcGxldGUgYmF0Y2hlcyAKYWxsQ29uZGl0aW9ucyA8LSBkYXRhW2RhdGEkYmF0Y2ggJWluJSBjb21wbGV0ZUJhdGNoZXMsIF0KYGBgCiMjIENvbmRpdGlvbmFsbHkgYXNzaWduIGNvbmRpdGlvbnMgYmFzZWQgb24gdHJlYXRtZW50IGFuZCByZXN1bHRzIGNvbHVtbjogCmBgYHtyfQojIyBNZXNzeSwgYnV0IHJvYnVzdD8gVmVyaWZ5LCB2ZXJpZnksIHZlcmlmeSBwZW9wbGU6ICAgCmRhdGEgPC0gZGF0YSAlPiUgbXV0YXRlKAogIGNvbmRpdGlvbiA9IGNhc2Vfd2hlbigKICAgIHJlc3VsdHMuY29uZGl0aW9uPT0ndHJlYXRtZW50JyAmIHJlc3VsdHMuZm9ybWF0PT0iYygxLCAyLCAxKSIgJiByb3VuZD09MSB+ICJBIiwgCiAgICByZXN1bHRzLmNvbmRpdGlvbj09J3RyZWF0bWVudCcgJiByZXN1bHRzLmZvcm1hdD09ImMoMSwgMiwgMSkiICYgcm91bmQ9PTIgfiAiQiIsIAogICAgcmVzdWx0cy5jb25kaXRpb249PSd0cmVhdG1lbnQnICYgcmVzdWx0cy5mb3JtYXQ9PSJjKDEsIDIsIDEpIiAmIHJvdW5kPT0zIH4gIkFwIiwgCiAgICByZXN1bHRzLmNvbmRpdGlvbj09J3RyZWF0bWVudCcgJiByZXN1bHRzLmZvcm1hdD09ImMoMSwgMSwgMikiICYgcm91bmQ9PTEgfiAiQSIsIAogICAgcmVzdWx0cy5jb25kaXRpb249PSd0cmVhdG1lbnQnICYgcmVzdWx0cy5mb3JtYXQ9PSJjKDEsIDEsIDIpIiAmIHJvdW5kPT0yIH4gIkFwIiwgCiAgICByZXN1bHRzLmNvbmRpdGlvbj09J3RyZWF0bWVudCcgJiByZXN1bHRzLmZvcm1hdD09ImMoMSwgMSwgMikiICYgcm91bmQ9PTMgfiAiQiIsIAogICAgcmVzdWx0cy5jb25kaXRpb249PSd0cmVhdG1lbnQnICYgcmVzdWx0cy5mb3JtYXQ9PSJjKDIsIDEsIDEpIiAmIHJvdW5kPT0xIH4gIkIiLCAKICAgIHJlc3VsdHMuY29uZGl0aW9uPT0ndHJlYXRtZW50JyAmIHJlc3VsdHMuZm9ybWF0PT0iYygyLCAxLCAxKSIgJiByb3VuZD09MiB+ICJBIiwgCiAgICByZXN1bHRzLmNvbmRpdGlvbj09J3RyZWF0bWVudCcgJiByZXN1bHRzLmZvcm1hdD09ImMoMiwgMSwgMSkiICYgcm91bmQ9PTMgfiAiQXAiICwKICAgIHJlc3VsdHMuY29uZGl0aW9uPT0nY29udHJvbCcgJiByZXN1bHRzLmZvcm1hdD09ImMoMSwgMiwgMSkiICYgcm91bmQ9PTEgfiAiQSIsIAogICAgcmVzdWx0cy5jb25kaXRpb249PSdjb250cm9sJyAmIHJlc3VsdHMuZm9ybWF0PT0iYygxLCAyLCAxKSIgJiByb3VuZD09MiB+ICJCIiwgCiAgICByZXN1bHRzLmNvbmRpdGlvbj09J2NvbnRyb2wnICYgcmVzdWx0cy5mb3JtYXQ9PSJjKDEsIDIsIDEpIiAmIHJvdW5kPT0zIH4gIkFwIiwgCiAgICByZXN1bHRzLmNvbmRpdGlvbj09J2NvbnRyb2wnICYgcmVzdWx0cy5mb3JtYXQ9PSJjKDEsIDEsIDIpIiAmIHJvdW5kPT0xIH4gIkEiLCAKICAgIHJlc3VsdHMuY29uZGl0aW9uPT0nY29udHJvbCcgJiByZXN1bHRzLmZvcm1hdD09ImMoMSwgMSwgMikiICYgcm91bmQ9PTIgfiAiQXAiLCAKICAgIHJlc3VsdHMuY29uZGl0aW9uPT0nY29udHJvbCcgJiByZXN1bHRzLmZvcm1hdD09ImMoMSwgMSwgMikiICYgcm91bmQ9PTMgfiAiQiIsIAogICAgcmVzdWx0cy5jb25kaXRpb249PSdjb250cm9sJyAmIHJlc3VsdHMuZm9ybWF0PT0iYygyLCAxLCAxKSIgJiByb3VuZD09MSB+ICJCIiwgCiAgICByZXN1bHRzLmNvbmRpdGlvbj09J2NvbnRyb2wnICYgcmVzdWx0cy5mb3JtYXQ9PSJjKDIsIDEsIDEpIiAmIHJvdW5kPT0yIH4gIkEiLCAKICAgIHJlc3VsdHMuY29uZGl0aW9uPT0nY29udHJvbCcgJiByZXN1bHRzLmZvcm1hdD09ImMoMiwgMSwgMSkiICYgcm91bmQ9PTMgfiAiQXAiICwKICAgIHJlc3VsdHMuY29uZGl0aW9uPT0nYmFzZWxpbmUnICYgcmVzdWx0cy5mb3JtYXQ9PSIxOjMiICYgcm91bmQ9PTEgfiAiQSIgLAogICAgcmVzdWx0cy5jb25kaXRpb249PSdiYXNlbGluZScgJiByZXN1bHRzLmZvcm1hdD09IjE6MyIgJiByb3VuZD09MiB+ICJCIiAsCiAgICByZXN1bHRzLmNvbmRpdGlvbj09J2Jhc2VsaW5lJyAmIHJlc3VsdHMuZm9ybWF0PT0iMTozIiAmIHJvdW5kPT0zIH4gIkMiIAogICkpIAoKYGBgCgojIyBTZXQtdXAgZm9yIGZhY3RvcnMgZm9yIHZpYWJpbGl0eSBxdWVzdGlvbnM6IApgYGB7cn0KZGF0YSA8LSByZW5hbWUoZGF0YSwgInJlcGVhdFRlYW0iID0gcmVzdWx0cy52aWFiaWxpdHlDaGVjay4xNSkKIyMgUmVtb3ZlIG9ic2VydmF0aW9ucyB3aGVyZSB2aWFiaWxpdHkgc3VydmV5IHdhc24ndCBvbiAocmVtb3ZlIHRoaXMgbGluZSBpZiB3ZSB3YW50IHRvIGtlZXAgb2JzZXJ2YXRpb25zIHdpdGggdmlhYmlsaXR5IG9mZik6IApkYXRhIDwtIG5hLm9taXQoZGF0YSkKIyMgRmFjdG9yIGZvciB2aXN1YWxpemF0aW9uczogCmxldmVscyA8LSBjKCJTdHJvbmdseSBEaXNhZ3JlZSIsICJEaXNhZ3JlZSIsICJOZXV0cmFsIiwiQWdyZWUiLCAiU3Ryb25nbHkgQWdyZWUiKSAKY2xlYW4gPC0gZGF0YSAlPiUgCiAgbXV0YXRlX2F0KC52YXJzID0gdmFycyhjb250YWlucygicmVzdWx0cy52aWFiaWxpdHlDaGVjayIpKSwgZnVucyhmYWN0b3IoLiwgbGV2ZWxzID0gbGV2ZWxzKSkpIAojIyBDcmVhdGUgYSBuZXcgZGF0YWZyYW1lIHRoYXQgY29udmVydHMgZmFjdG9ycyB0byBudW1lcmljIGZvciBzdGF0aXN0aWNhbCBhbmFseXNlczoKc3RhdHMgPC0gY2xlYW4gJT4lIG11dGF0ZV9pZihpcy5mYWN0b3IsIGFzLm51bWVyaWMpCmZvciAoaSBpbiAxOm5yb3coc3RhdHMpKSB7CiAgc3RhdHMkc3VtW2ldIDwtIHN1bShzdGF0c1tpLDE6MTRdKSAgICAgICAgICAgICAgICAgICAgICAgICAgCn0gCnN0YXRzJG1lZGlhbiA8LSBtZWRpYW4oc3RhdHMkc3VtKQpzdGF0cyRtZWFuIDwtIG1lYW4oc3RhdHMkc3VtKQojIyBSZXZhbHVlIHJlcGVhdCB0ZWFtOiBrZWVwIHBseXIgYi9jIHNvbWUgd2VpcmQgUiBzdHVmZiByZXF1aXJlcyBsaWJyYXJ5IHRvIGJlIGNhbGxlZCBkaXJlY3RseSAocmVjb2RlIHZhbHVlcyB0byApCnN0YXRzJHJlcGVhdFRlYW0gPC0gcGx5cjo6cmV2YWx1ZShzdGF0cyRyZXBlYXRUZWFtLCBjKCJZZXMiPSIwIiwgIk5vIj0iMSIpKQpzdGF0cyRyZXBlYXRUZWFtIDwtIHBseXI6OnJldmFsdWUoc3RhdHMkcmVwZWF0VGVhbSwgYygiS2VlcCB0aGlzIHRlYW0iPSIwIiwgIkRvIG5vdCBrZWVwIHRoaXMgdGVhbSI9IjEiKSkKIyMgQ29udmVydCB0byBjb21wYXRpYmxlIGNsYXNzZXMgZm9yIHRlYW0gZ3JvdXBpbmc6IApzdGF0cyRyZXBlYXRUZWFtIDwtIGFzLm51bWVyaWMoc3RhdHMkcmVwZWF0VGVhbSkKc3RhdHMkcmVzdWx0cy5jb25kaXRpb24gPC0gdW5saXN0KHN0YXRzJHJlc3VsdHMuY29uZGl0aW9uKQpzdGF0cyRyZXN1bHRzLmZvcm1hdCA8LSBhcy5jaGFyYWN0ZXIoc3RhdHMkcmVzdWx0cy5mb3JtYXQpCnN0YXRzJHJvb20gPC0gdW5saXN0KHN0YXRzJHJvb20pCiMjIERwbHlyIHRvIGdyb3VwIHRlYW1zIGFuZCBzdW1tYXJpc2UgdmFyaWFibGVzIGZvciBlYWNoIGdyb3VwOiBncm91cF9ieSB0byBmaW5kIHRlYW1zIGFuZCBzdW1tYXJpc2UgdG8gY29tcGFjdCBpbmRpdmlkdWFsIHJlc3VsdHMgaW50byBncm91cCBsZXZlbCByZXN1bHRzIChpLmUuIG9uZSByb3cgb2YgdmFyaWFibGUgcmVzdWx0cyBwZXIgdGVhbSkKZ3JvdXBlZFByb3BvcnRpb24gPC0gc3RhdHMgJT4lCiAgZ3JvdXBfYnkocm9vbSwgYmF0Y2gsIHJvdW5kLCBjb25kaXRpb24sIHJlc3VsdHMuY29uZGl0aW9uLCByZXN1bHRzLmZvcm1hdCkgJT4lICAjIyB0by1kbzogYWRkIGdyb3VwIElEIGluIHN0b3JhZ2UgZGIuIAogIHN1bW1hcmlzZShuPW4oKSwgbWVhbj1tZWFuKHN1bSksIG1lZGlhbj1tZWRpYW4oc3VtKSxwcm9wPXN1bShyZXBlYXRUZWFtKS9uLCBncm91cElEPXJ1bmlmKDEsMCwyKSkgJT4lIAojIyBGaWx0ZXIgb3V0IGFsbCB0ZWFtcyB3aXRoIG49MSAoaS5lLiBhIHBlcnNvbiBpbiBhIG9uZSBwZXJzb24gdGVhbSkgCiAgZmlsdGVyKG49PTIpCgojIyBJbmRpdmlkdWFsIHByb3BvcnRpb246IAppbmRpdmlkdWFsUHJvcG9ydGlvbiA8LSBzdGF0cyAlPiUgZ3JvdXBfYnkocm91bmQsIGJhdGNoLCByb29tKSAlPiUgCiAgbXV0YXRlKHN1bT1zdW0sIG1lYW49bWVhbihzdW0pLCBtZWRpYW49bWVkaWFuKHN1bSksIG49bigpLHByb3A9c3VtKHJlcGVhdFRlYW0pL24pICU+JSAKICBmaWx0ZXIobj4xKQoKIyMgVGFibGUgc2hvd2luZyBob3cgbWFueSB0ZWFtcyB3ZSd2ZSBydW4gaW4gZWFjaCBjb25kaXRpb24gY29tYmluYXRpb246ICAKcHJpbnQodGFibGUoZ3JvdXBlZFByb3BvcnRpb24kY29uZGl0aW9uLCBncm91cGVkUHJvcG9ydGlvbiRyZXN1bHRzLmNvbmRpdGlvbikpIApgYGAKCiMjIFByb2JhYmlsaXR5IG9mIGZyYWN0dXJlIGFjcm9zcyB0ZWFtcyBhbmQgY29uZGl0aW9uIGNvbWJpbmF0aW9uczogCmBgYHtyfQojIyBEZWZpbmUgYW5kIGluaXRpYWxpemUgY3V0LW9mZiBwb2ludCBmb3IgZnJhY3R1cmU6IApncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlIDwtIGdyb3VwZWRQcm9wb3J0aW9uICU+JQogIGdyb3VwX2J5KHJlc3VsdHMuY29uZGl0aW9uLCBjb25kaXRpb24pICU+JSAKICBtdXRhdGUoZnJhY3R1cmUgPSBjYXNlX3doZW4gKHByb3A8LjUwIH4gIjAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9wPj0uNTB+ICIxIikpIAoKIyMgQmFzZWxpbmU6ICh3ZSBwcm9iYWJseSB3b24ndCBuZWVkIHRoaXMgc2luY2Ugd2UgYXJlIGFydGlmaWNpYWxseSBtYWtpbmcgYmFzZWxpbmUgY29uZGl0aW9ucykKIyBncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlQmFzZWxpbmUgPC0gCiMgICBncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlICU+JSAKIyBmaWx0ZXIocmVzdWx0cy5jb25kaXRpb249PSJiYXNlbGluZSIpICU+JSAKIyAgIGZpbHRlcihpZCAlaW4lIGNvbmRpdGlvbj09IkEiICYgY29uZGl0aW9uPT0iQyIpCiMgYmFzZWxpbmVGcmFjdHVyZTEgPC0gZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZUJhc2VsaW5lICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0iQSIpCiMgYmFzZWxpbmVGcmFjdHVyZTIgPC0gZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZUJhc2VsaW5lICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0iQyIpCgojIFRPLURPOiBjaGVjayBpZiB0aGlzIGlzIHJpZ2h0LS1zZWVtcyBvZmYgKHdoeSBpcyBiYXNlbGluZSBvZmY/KQoKZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZUJhc2VsaW5lIDwtIGdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmUgJT4lIGZpbHRlcihyZXN1bHRzLmZvcm1hdD09ImMoMSwgMSwgMikiIHwgcmVzdWx0cy5mb3JtYXQ9PSJjKDIsIDEsIDEpIikgJT4lIGZpbHRlcihyb3VuZD09IjEiIHwgcm91bmQ9PSIzIikgCmJhc2VsaW5lRnJhY3R1cmUxIDwtIGdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmVCYXNlbGluZSAlPiUgZmlsdGVyKHJvdW5kPT0iMSIpCmJhc2VsaW5lRnJhY3R1cmUyIDwtIGdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmVCYXNlbGluZSAlPiUgZmlsdGVyKHJvdW5kPT0iMyIpCmJhc2VsaW5lRnJhY3R1cmUxJGZyYWN0dXJlMSA8LSBiYXNlbGluZUZyYWN0dXJlMSRmcmFjdHVyZQpiYXNlbGluZUZyYWN0dXJlMiRmcmFjdHVyZTIgPC0gYmFzZWxpbmVGcmFjdHVyZTIkZnJhY3R1cmUKIyMgQmVsb3cgb25seSBjb21iaW5lcyBpZiB0ZWFtcyBhcmUgaW4gYm90aCByb3VuZCAxICYgMyB0b2dldGhlcjogCgojIyBUcmVhdG1lbnQ6IApncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlVHJlYXRtZW50IDwtIGdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmUgJT4lIApmaWx0ZXIocmVzdWx0cy5jb25kaXRpb249PSJ0cmVhdG1lbnQiKQp0cmVhdG1lbnRGcmFjdHVyZTEgPC0gZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZVRyZWF0bWVudCAlPiUgZmlsdGVyKGNvbmRpdGlvbj09IkEiKQp0cmVhdG1lbnRGcmFjdHVyZTIgPC0gZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZVRyZWF0bWVudCAlPiUgZmlsdGVyKGNvbmRpdGlvbj09IkFwIikKdHJlYXRtZW50RnJhY3R1cmUgPC0gY2JpbmQodHJlYXRtZW50RnJhY3R1cmUxLCB0cmVhdG1lbnRGcmFjdHVyZTIpCgojIyBDb250cm9sOiAgCmdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmVDb250cm9sIDwtIGdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmUgJT4lIAogIGZpbHRlcihyZXN1bHRzLmNvbmRpdGlvbj09ImNvbnRyb2wiKSAKY29udHJvbEZyYWN0dXJlMSA8LSBncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlQ29udHJvbCAlPiUgZmlsdGVyKGNvbmRpdGlvbj09IkEiKQpjb250cm9sRnJhY3R1cmUyIDwtIGdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmVDb250cm9sICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0iQXAiKQpjb250cm9sRnJhY3R1cmUgPC0gY2JpbmQoY29udHJvbEZyYWN0dXJlMSwgY29udHJvbEZyYWN0dXJlMikKCiMjIE1hbmlwdWxhdGlvbiBjaGVjazogCiMjIFVzZSBpbmRpdmlkdWFsIHByb3BvcnRpb24gZGF0YSBmcmFtZSBiL2Mgd2UncmUgaW50ZXJlc3RlZCBpbiBsb29raW5nIGF0IGluZGl2aWR1YWxzIHRoYXQgd2VyZSBpbiB0ZWFtcyA+bj0xCnRlYW1QYXR0ZXJucyA8LSAiVGVhbSAxIGFuZCBUZWFtIDJ8VGVhbSAxIGFuZCBUZWFtIDN8VGVhbSAyIGFuZCBUZWFtIDMiCmluZGl2aWR1YWxQcm9wb3J0aW9uJG1hbmlwdWxhdGlvbkFuc3dlcktleSA8LSBzdHJfZXh0cmFjdChpbmRpdmlkdWFsUHJvcG9ydGlvbiRyZXN1bHRzLm1hbmlwdWxhdGlvbkNoZWNrLHRlYW1QYXR0ZXJucykgCmluZGl2aWR1YWxQcm9wb3J0aW9uJG1hbmlwdWxhdGlvbkFuc3dlcnMgPC0gaW5kaXZpZHVhbFByb3BvcnRpb24kcmVzdWx0cy5tYW5pcHVsYXRpb24KaW5kaXZpZHVhbFByb3BvcnRpb24kcmVzdWx0cy5jb25kaXRpb24gPSB1bmxpc3QoaW5kaXZpZHVhbFByb3BvcnRpb24kcmVzdWx0cy5jb25kaXRpb24pCiMjIE9taXQgTkFzIGFuZCByZXN1bHRzIHRoYXQgY2FuJ3QgYmUgcHJvY2Vzc2VkOiAKY2xlYW5NYW5pcHVsYXRpb24gPC0gaW5kaXZpZHVhbFByb3BvcnRpb25bd2l0aChpbmRpdmlkdWFsUHJvcG9ydGlvbiwgZ3JlcGwodGVhbVBhdHRlcm5zLCBtYW5pcHVsYXRpb25BbnN3ZXJzKSAmIGdyZXBsKHRlYW1QYXR0ZXJucywgbWFuaXB1bGF0aW9uQW5zd2VyS2V5KSksXQojIyBUcmFuc2Zvcm0gaW50byBjb21wYXRpYWJsZSBmb3JtOiAKY2xlYW5NYW5pcHVsYXRpb24kbWFuaXB1bGF0aW9uQW5zd2VycyA9IHVubGlzdChjbGVhbk1hbmlwdWxhdGlvbiRtYW5pcHVsYXRpb25BbnN3ZXJzKQpgYGAKCiMjIFNlY3Rpb24gIzE6IERvZXMgZnJhY3R1cmUgaGF2ZSBjb250aW51aXR5IHdpdGggcHJpb3IgbWVhc3VyZXM/CgojIyAxQTogUmVwb3J0IHRoZSAlIG9mIGNvcnJlY3QgZ3Vlc3NlcyBvbiB0aGUgbWFuaXB1bGF0aW9uIGNoZWNrOiAKYGBge3J9CiMjIFRyZWF0bWVudCBtYW5pcHVsYXRpb246IAp0cmVhdG1lbnRNYW5pcHVsYXRpb24gPC0gY2xlYW5NYW5pcHVsYXRpb24gJT4lIGdyb3VwX2J5KGlkLCByZXN1bHRzLmNvbmRpdGlvbiwgbWFuaXB1bGF0aW9uQW5zd2VycywgbWFuaXB1bGF0aW9uQW5zd2VyS2V5KSAlPiUgZmlsdGVyKHJlc3VsdHMuY29uZGl0aW9uPT0idHJlYXRtZW50IikgJT4lIAogIHN1bW1hcmlzZShuPW4oKSkgCiMjIElmIHVzZXIgbWFuaXB1bGF0aW9uIGFuc3dlcnMgPT0gbWFuaXB1bGF0aW9uIGFuc3dlciBrZXkgdGhlbiBhZGQgMSAKdHJlYXRtZW50TWFuaXB1bGF0aW9uJGNvcnJlY3RBbnN3ZXJzIDwtIHN1bShpZmVsc2UodHJlYXRtZW50TWFuaXB1bGF0aW9uJG1hbmlwdWxhdGlvbkFuc3dlcnM9PXRyZWF0bWVudE1hbmlwdWxhdGlvbiRtYW5pcHVsYXRpb25BbnN3ZXJLZXksMSwwKSkKIyMgQ2FsY3VsYXRlIHBlcmNlbnQgb2YgY29ycmVjdCBtYW5pcHVsYXRpb24gYW5zd2VycyBmb3IgdHJlYXRtZW50OiAKdHJlYXRtZW50TWFuaXB1bGF0aW9uIDwtIHRyZWF0bWVudE1hbmlwdWxhdGlvbiAlPiUgbXV0YXRlKHBlcmNlbnRDb3JyZWN0ID0gKGNvcnJlY3RBbnN3ZXJzLyhucm93KHRyZWF0bWVudE1hbmlwdWxhdGlvbikpKSkKCiMjIENvbnRyb2wgbWFuaXB1bGF0aW9uOiAKY29udHJvbE1hbmlwdWxhdGlvbiA8LSBjbGVhbk1hbmlwdWxhdGlvbiAlPiUgZ3JvdXBfYnkoaWQsIHJlc3VsdHMuY29uZGl0aW9uLCBtYW5pcHVsYXRpb25BbnN3ZXJzLCBtYW5pcHVsYXRpb25BbnN3ZXJLZXkpICU+JSBmaWx0ZXIocmVzdWx0cy5jb25kaXRpb249PSJjb250cm9sIikgJT4lIAogIHN1bW1hcmlzZShuPW4oKSkgCiMjIElmIHVzZXIgbWFuaXB1bGF0aW9uIGFuc3dlcnMgPT0gbWFuaXB1bGF0aW9uIGFuc3dlciBrZXkgdGhlbiBhZGQgMSAKY29udHJvbE1hbmlwdWxhdGlvbiRjb3JyZWN0QW5zd2VycyA8LSBzdW0oaWZlbHNlKGNvbnRyb2xNYW5pcHVsYXRpb24kbWFuaXB1bGF0aW9uQW5zd2Vycz09Y29udHJvbE1hbmlwdWxhdGlvbiRtYW5pcHVsYXRpb25BbnN3ZXJLZXksMSwwKSkKIyMgQ2FsY3VsYXRlIHBlcmNlbnQgb2YgY29ycmVjdCBtYW5pcHVsYXRpb24gYW5zd2VycyBmb3IgY29udHJvbDogCmNvbnRyb2xNYW5pcHVsYXRpb24gPC0gY29udHJvbE1hbmlwdWxhdGlvbiAlPiUgbXV0YXRlKHBlcmNlbnRDb3JyZWN0ID0gKGNvcnJlY3RBbnN3ZXJzLyhucm93KGNvbnRyb2xNYW5pcHVsYXRpb24pKSkpCiMjIFByb3BvcnRpb24gdGVzdCBjb21wYXJpbmcgdHJlYXRtZW50IG1hbmlwdWxhdGlvbiBwZXJjZW50IGNvcnJlY3Qgd2l0aCBjaGFuY2U6IApgYGAKCiMjIDFCOiBQcm9wb3J0aW9uIHRlc3QgY29tcGFyaW5nIHRyZWF0bWVudCBtYW5pcHVsYXRpb24gcGVyY2VudCBjb3JyZWN0IHdpdGggY2hhbmNlOiAKYGBge3J9CiMjIOKFkyB+IDMzJSA9IGNoYW5jZSwgfjQzID0gdHJlYXRtZW50IChGSUxMLUlOIEVBQ0ggVElNRSBZT1UgUlVOIFdJVEggTkVXIERBVEEhKQoKcHJvcE1hbmlwdWxhdGlvbiA8LSBwcm9wLnRlc3QoeCA9IGMoMzMsIDQzKSwgbiA9IGMoMTAwLCAxMDApKQpwcmludChwcm9wTWFuaXB1bGF0aW9uKQpgYGAKCiMjIDFDOiBMb2dpc3RpYyByZWdyZXNzaW9uIHByZWRpY3RpbmcgYmluYXJ5IGZyYWN0dXJlIG91dGNvbWUgZnJvbSB2aWFiaWxpdHkgc2NhbGVzOiAKYGBge3J9CiMjIFNwbGl0IGRhdGEgaW50byA2MCUgdHJhaW5pbmcgYW5kIDQwJSB0ZXN0aW5nIGRhdGEgc2V0cyB0byB0ZXN0IGhvdyB3ZWxsIHRoZSBtb2RlbCBwZXJmb3JtcyAKc2V0LnNlZWQoMTIzKQpncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlJGZyYWN0dXJlIDwtIGFzLm51bWVyaWMoZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZSRmcmFjdHVyZSkgCnNhbXBsZSA8LSBzYW1wbGUoYyhUUlVFLCBGQUxTRSksIG5yb3coZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZSksIHJlcGxhY2UgPSBULCBwcm9iID0gYygwLjYsMC40KSkKdHJhaW4gPC0gZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZVtzYW1wbGUsIF0KdGVzdCA8LSBncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlWyFzYW1wbGUsIF0KCiMjIFNpbXBsZSBsb2dpc3RpYyByZWdyZXNzaW9uOiB3ZSB3aWxsIGZpdCBhIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgaW4gb3JkZXIgdG8gcHJlZGljdCAKIyMgdGhlIHByb2JhYmlsaXR5IG9mIGZyYWN0dXJlIGJhc2VkIG9uIGEgdGVhbSdzIGF2ZXJhZ2UgdmlhYmlsaXR5IHN1bTogCgptb2RlbDEgPC0gZ2xtKGZyYWN0dXJlIH4gbWVhbiwgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IHRyYWluKQpzdW1tYXJ5KG1vZGVsMSkKCiMjIFRvIGFzc2VzcyB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gZGV2aWFuY2UsIGxvb2sgYXQgZGV2aWFuY2UgaW4gc3VtbWFyeSBvdXRwdXQsIGlmIAojIyBkZXZpYW5jZSA9PSBzdW0gb2Ygc3FhdXJlcyBpbiBsaW5lYXIgcmVncmVzc2lvbiwgbnVsbCBkZXZpYW5jZSA9PSBkaWZmZXJlbmNlIGJldHdlZW4gCiMjIGEgbW9kZWwgd2l0aCBvbmx5IHRoZSBpbnRlcmNlcHQgKCJubyBtZWFuIHByZWRpY3RvcnMiKSBhbmQgdGhlIGEgc2F0dXJhdGVkIG1vZGVsIAojIyBhIG1vZGVsIHdpdGggYSB0aGVvcmV0aWNhbGx5IHBlcmZlY3QgZml0LiBNb2RlbCBkZXZpYW5jZSAocmVzaWR1YWwgZGV2aWFuY2UpIHNob3VsZCBiZSBsb3dlciAKIyMgc21hbGwgdmFsdWVzID09IGJldHRlciBmaXQuIAoKdGlkeShtb2RlbDEpCiMjIENvZWZmaWNpZW50IGVzdGltdGVzIGZyb20gbG9nIHJlZ3Jlc3Npb24gY2hhcmFjdGVyaXplIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBwcmVkaWN0b3IgYW5kIAojIyByZXNwb25zZSB2YXJpYWJsZSBvbiBhIGxvZy1vZGRzIHNjYWxlLCBzbyBiaW5hcnkgaW5jcmVhc2UgZnJvbSBubyBmcmFjdHVyZSAtIGZyYWN0dXJlIGNhbiBiZSBpbnRlcnByZXRlZCBhcyBhc3NvY2lhdGVkIHdpdGggYSBkZWNyZWFzZSBpbiBtZWFuIHZpYWJpbGl0eSBzdW0uIAoKIyMgTW9yZSBjb2VmZmljaWVudCBvdXRwdXQ6IG1lYXN1cmUgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGFuZCBhY2N1cmFjeSBvZiB0aGUgY29lZmZpY2VudDogCmNvbmZpbnQobW9kZWwxKQoKIyMgTWFraW5nIHByZWRpY3Rpb25zOiAKIyMgV2hhdCBpcyB0aGUgcHJvYmFiaWxpdHkgb2YgZnJhY3R1cmUgZ2l2ZW4gdGhlIGZvbGxvd2luZyB0ZWFtIG1lYW4gdmlhYmlsaXR5IHNjb3JlczogZm9yIGV4YW1wbGUgcHVycG9zZXM6IDQwIGFuZCA2NTogCgpwcmVkaWN0KG1vZGVsMSwgZGF0YS5mcmFtZShtZWFuID0gYyg1MCwgNjUpKSwgdHlwZSA9ICJyZXNwb25zZSIpCgojIyBGcm9tIHRoZSBvdXRwdXQsIHdlIGNhbiBzZWUgdGhhdCB0aGUgcHJvYmFiaWxpdHkgb2YgZnJhY3R1cmUgZGVjcmVhc2VzIGJ5IH40MCUgd2hlbiBtZWFuIHZpYWJpbGl0eSBzdW0gaW5jcmVhc2VzIGZyb20gNDAgdG8gNjUuIAoKIyMgTW9kZWwgZXZhbHVhdGlvbiAmIGRpYWdub3N0aWNzOiAKIyMgSG93IHdlbGwgZG9lcyB0aGUgbW9kZWwgZml0IHRoZSBkYXRhPyBBbmQgaG93IGFjY3VyYXRlIGFyZSB0aGUgcHJlZGljdGlvbnMgb24gYW4gb3V0LW9mLXNhbXBsZSBkYXRhIHNldD8KCiMjIFJlc2lkdWwgYXNzZXNzbWVudDogCgptb2RlbDFfZGF0YSA8LSBhdWdtZW50KG1vZGVsMSkgJT4lIAogIG11dGF0ZShpbmRleCA9IDE6bigpKQoKZ2dwbG90KG1vZGVsMV9kYXRhLCBhZXMoaW5kZXgsIC5zdGQucmVzaWQsIGNvbG9yID0gbWVhbikpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IC41KSArCiAgZ2VvbV9yZWZfbGluZShoID0gMykKCiMjIFZhbGlkYXRpb24gb2YgcHJlZGljdGVkIHZhbHVlczogCiMjIEhvdyB3ZWxsIGRvZXMgdGhlIG1vZGVsIHBlcmZvcm0gd2hlbiBwcmVkaWN0aW5nIHRoZSB0YXJnZXQgdmFyaWFibGUgb24gb3V0LW9mLXNhbXBsZSBvYnNlcnZhdGlvbnM/IAoKdGVzdC5wcmVkaWN0ZWQubTEgPC0gcHJlZGljdChtb2RlbDEsIG5ld2RhdGEgPSB0ZXN0LCB0eXBlID0gInJlc3BvbnNlIikKCiMjIENsYXNzaWZpY2F0aW9uIHBlcmZvcm1hbmNlIGZvciBlYWNoIG1vZGVsIG9uIHRoZSB0ZXN0IGRhdGEuIE91dHB1dCBnaXZlcyB1cyBhIGxpc3Qgb2YgdHJ1ZSAvIGZhbHNlIHBvc2l0aXZlczogCgpsaXN0KAogIG1vZGVsMSA9IHRhYmxlKHRlc3QkbWVhbiwgdGVzdC5wcmVkaWN0ZWQubTEgPiAwLjUpICU+JSBwcm9wLnRhYmxlKCkgJT4lIHJvdW5kKDMpKSAKCnRhYmxlKHRlc3QkbWVhbiwgdGVzdC5wcmVkaWN0ZWQubTEgPiAwLjUpCmBgYAojIyAxRDogR3JhcGggb2YgZnJhY3R1cmUvbm8gZnJhY3R1cmUgdnMuIG1lYW4vc3RkZXYgdmlhYmlsaXR5IHNjYWxlCgpgYGB7cn0KIyMgT3ZlcmFsbDogCmcgPC0gZ2dwbG90KGdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmUsIGFlcyhmYWN0b3IoZnJhY3R1cmUpLCBtZWFuKSkgCmcgKyBnZW9tX2JveHBsb3QodmFyd2lkdGg9VCwgZmlsbD0icGx1bSIpICsgCiAgbGFicyhzdWJ0aXRsZT0iVGVhbSBmcmFjdHVyZSB2YWx1ZSB2cy4gbWVhbiB2aWFiaWxpdHkgc2NvcmU6IGZyYWN0dXJlID49MC41MCBhY3Jvc3MgYWxsIGNvbmRpdGlvbnMgKG49MikiLCAKICAgICAgIHg9IiIsCiAgICAgICB5PSJOdW1lcmljIHN1bSBvZiB2aWFiaWxpdHkgbWVhc3VyZXMgcXVlc3Rpb25zIChyYW5nZTogNy03MCkiKSAKCmBgYAoKYGBge3J9CiMjIEJ5IGNvbmRpdGlvbiArIGZvcm1hdDogCmcgPC0gZ2dwbG90KGdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmUsIGFlcyhmYWN0b3IoZnJhY3R1cmUpLCBtZWFuKSkgCmcgKyBnZW9tX2JveHBsb3QodmFyd2lkdGg9VCwgZmlsbD0icGx1bSIpICsgCiAgbGFicyhzdWJ0aXRsZT0iVGVhbSBmcmFjdHVyZSB2YWx1ZSB2cy4gbWVhbiB2aWFiaWxpdHkgc2NvcmU6IGZyYWN0dXJlID49MC41MCAobj0yKSIsIAogICAgICAgeD0iIiwKICAgICAgIHk9Ik51bWVyaWMgc3VtIG9mIHZpYWJpbGl0eSBtZWFzdXJlcyBxdWVzdGlvbnMgKHJhbmdlOiA3LTcwKSIpICsgZmFjZXRfZ3JpZChjb25kaXRpb24gfiByZXN1bHRzLmNvbmRpdGlvbikgCmBgYAoKYGBge3J9CmdncGxvdChkYXRhPWdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmUsIGFlcyhmcmFjdHVyZSwgbWVhbikpICsgCiAgIGdlb21fcG9pbnQoKSArCiAgc3RhdF9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sID0gInJlZCIpICsgbGFicyhtYWluPSJTY2F0dGVycGxvdCBvZiBmcmFjdHVyZSB2YWx1ZSB2cy4gbWVhbiBmb3IgdGVhbSB2aWFiaWxpdHkgc3VtcyBhY3Jvc3MgYWxsIGNvbmRpdGlvbnMgKG49MikiKSArICBmYWNldF9ncmlkKGNvbmRpdGlvbiB+IHJlc3VsdHMuY29uZGl0aW9uKSAKYGBgCgpgYGB7cn0KZ2dwbG90KGRhdGE9Z3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZSwgYWVzKGZyYWN0dXJlLCBtZWFuKSkgKyAKICAgZ2VvbV9wb2ludCgpICsKICBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iLCBjb2wgPSAicmVkIikgKyBsYWJzKG1haW49IlNjYXR0ZXJwbG90IG9mIGZyYWN0dXJlIHZhbHVlIHZzLiBtZWFuIGZvciB0ZWFtIHZpYWJpbGl0eSBzdW1zIChuPTIpIikgKyAgZmFjZXRfZ3JpZChjb25kaXRpb24gfiByZXN1bHRzLmNvbmRpdGlvbikgCmBgYAoKIyMgU2VjdGlvbiAjMjogSG93IG9mdGVuIGRvZXMgZnJhY3R1cmUgb2NjdXI/CgojIyAyQTogUChiaW5hcnkgZnJhY3R1cmUpIGhpc3RvZ3JhbSBvZiBmcmFjdHVyZSBwcm9wb3J0aW9uIChieSB0ZWFtKQpgYGB7cn0KIyMgRmlyc3QgbWFrZSBzdXJlIHlvdSd2ZSBtYWRlIEFCQyBjb25kaXRpb24KZ2dwbG90KGRhdGE9Z3JvdXBlZFByb3BvcnRpb24sIGFlcyhncm91cGVkUHJvcG9ydGlvbiRwcm9wKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShicmVha3M9c2VxKDAsIDEsIGJ5PTAuMjApLCAKICAgICAgICAgICAgICAgICBjb2w9InJlZCIsIAogICAgICAgICAgICAgICAgIGZpbGw9ImdyZWVuIiwgCiAgICAgICAgICAgICAgICAgYWxwaGE9LjIpICsgbGFicyh0aXRsZT0iRnJlcXVlbmN5IG9mIHRlYW0gZnJhY3R1cmUgcHJvcG9ydGlvbnMgYnkgY29uZGl0aW9uIGFuZCBwYXR0ZXJuIHNlcXVlbmNlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4PSJ0ZWFtIGZyYWN0dXJlIHByb3BvcnRpb24iLCB5PSJDb3VudCIpICsgZmFjZXRfZ3JpZChyZXN1bHRzLmNvbmRpdGlvbiB+IC4pIApgYGAKYGBge3J9CmdncGxvdChkYXRhPWdyb3VwZWRQcm9wb3J0aW9uLCBhZXMoZ3JvdXBlZFByb3BvcnRpb24kcHJvcCkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oYnJlYWtzPXNlcSgwLCAxLCBieT0wLjIwKSwgCiAgICAgICAgICAgICAgICAgY29sPSJyZWQiLCAKICAgICAgICAgICAgICAgICBmaWxsPSJncmVlbiIsIAogICAgICAgICAgICAgICAgIGFscGhhPS4yKSArIGxhYnModGl0bGU9IkZyZXF1ZW5jeSBvZiB0ZWFtIGZyYWN0dXJlIHByb3BvcnRpb25zIGJ5IGNvbmRpdGlvbiBhbmQgcGF0dGVybiBzZXF1ZW5jZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeD0idGVhbSBmcmFjdHVyZSBwcm9wb3J0aW9uIiwgeT0iQ291bnQiKSArIGZhY2V0X2dyaWQocmVzdWx0cy5jb25kaXRpb24gfiBjb25kaXRpb24pICAKYGBgCgpgYGB7cn0KbGlicmFyeShNQVNTKSAgICAgCgojIyBUZXN0IGlmIHdoZXRoZXIgZnJhY3R1cmUgc21va2luZyBoYWJpdCBpcyBpbmRlcGVuZGVudCBvZiBjb25kaXRpb24gYXQgLjA1IHNpZ25pZmljYW5jZSBsZXZlbDogCgpjaGkgPSB0YWJsZShncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlJGZyYWN0dXJlLCBncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlJHJlc3VsdHMuY29uZGl0aW9uKSAgCmNoaQpwcmludChjaGlzcS50ZXN0KGNoaSkpIApgYGAKCiMjIDJCOiBXaGF0J3MgdGhlIG92ZXJhbGwgJSBvZiBmcmFjdHVyaW5nIHRoZSBzZWNvbmQgdGltZT8gKGJ5IGNvbmRpdGlvbikKYGBge3J9CiMjIEZpbHRlcmluZyBzZWNvbmQgdGltZSBvbmx5OiAKZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZSRmcmFjdHVyZSA8LSBhcy5udW1lcmljKGdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmUkZnJhY3R1cmUpCgojIyBUTy1ETzogcmV2aWV3IGJlbG93IGNvZGUsIHdvcnJpZWQgaXQncyBpbmNvcnJlY3Q6IAoKZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZVNlY29uZCA8LSBncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlICU+JSBncm91cF9ieShyZXN1bHRzLmNvbmRpdGlvbikgJT4lIAogICAgICBmaWx0ZXIoY29uZGl0aW9uPT0iQXAiKSAlPiUgCiAgICAgIG11dGF0ZShvdmVyYWxsUGVyY2VudCA9IHN1bShhcy5udW1lcmljKGZyYWN0dXJlKSkpICU+JSAKICAgICAgc3VtbWFyaXNlKG49bigpLCBvdmVyYWxsUGVyY2VudD11bmlxdWUob3ZlcmFsbFBlcmNlbnQpL24pIApwcmludChncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlU2Vjb25kKQoKIyMgRm9yIGJhc2VsaW5lIHRoZW9yZXRpY2FsIGRpc3RyaWJ1dGlvbjogKHRvLWRvOiBsb29rIG92ZXIgdGhpcywgd29ycmllZCBhbHNvIHRoYXQgaXQncyB3cm9uZykKCmdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmVTZWNvbmRCYXNlIDwtIGdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmVCYXNlbGluZSAlPiUgCiAgICAgIGZpbHRlcihyb3VuZD09IjMiKSAlPiUgCiAgICAgIHN1bW1hcmlzZShuPW4oKSwgb3ZlcmFsbFBlcmNlbnQ9c3VtKGFzLm51bWVyaWMoZnJhY3R1cmUpKS9uKSAKcHJpbnQobWVhbihncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlU2Vjb25kQmFzZSRvdmVyYWxsUGVyY2VudCkpCgojIyBTZXQtdXAgc2VwYXJhdGUgZ3JvdXBzIGZvciBwcm9wb3J0aW9uIHRlc3RzIHRvIGFuc3dlcjogZG9lcyB1bm1hc2tlZCBmcmFjdHVyZSBtb3JlL2xlc3MgdGhhbiBtYXNrZWQsIGFuZCBtb3JlL2xlc3MgdGhhbiBuZXcgcGFpcnM/IAoKIyMgQ29udHJvbDogCiMjIFByb3BvcnRpb24gdGVzdHMgZm9yIGVhY2ggKFRPLURPLCBmaWd1cmUgb3V0IGFyZ3VtZW50IHN0dWZmOiB0aGlzIGRvZXNuJ3Qgc2VlbSBsaWtlIHRoZSByaWdodCB0ZXN0IHRvIHJ1biBmb3IgdGhlIHF1ZXN0aW9uIHdlJ3JlIGFza2luZz8pIGFsc28sIGZpbGwtdGhpcyBpbiBldmVyeSB0aW1lIHlvdSBnZXQgbmV3IGRhdGE6IAoKIyMgSXMgdGhlIHByb3BvcnRpb24gb2YgZnJhY3R1cmUgaW4gdGhlIHNlY29uZCByb3VuZCBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBpbiB0aGUgdHdvIGNvbmRpdGlvbnMgKGkuZS4gdHJlYXRtZW50ICsgYmFzZWxpbmUpIAp0cmVhdG1lbnR2c0Jhc2VsaW5lQ2hhbmdlIDwtIGMoNDgsIDQ5KQpwcm9wRnJhY3R1cmVDaGFuZ2VUcmVhdG1lbnR2c0Jhc2UgPC0gcHJvcC50ZXN0KHggPSBjKHRyZWF0bWVudHZzQmFzZWxpbmVDaGFuZ2UpLCBuID0gYygxMDAsIDEwMCkpCnByaW50KHByb3BGcmFjdHVyZUNoYW5nZVRyZWF0bWVudHZzQmFzZSkgCgojIyBJcyB0aGUgcHJvcG9ydGlvbiBvZiBmcmFjdHVyZSBpbiB0aGUgc2Vjb25kIHJvdW5kIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGluIHRoZSB0d28gY29uZGl0aW9ucyAoaS5lLiBjb250cm9sICsgYmFzZWxpbmUpIApjb250cm9sdnNCYXNlbGluZUNoYW5nZSA8LSBjKDQwLCA0OSkKcHJvcEZyYWN0dXJlQ2hhbmdlQ29udHJvbHZzQmFzZSA8LSBwcm9wLnRlc3QoeCA9IGMoY29udHJvbHZzQmFzZWxpbmVDaGFuZ2UpLCBuID0gYygxMDAsIDEwMCkpCnByaW50KHByb3BGcmFjdHVyZUNoYW5nZUNvbnRyb2x2c0Jhc2UpCmBgYAojIyBTZWN0aW9uIDM6IEhvdyBjb25zaXN0ZW50IGlzIGZyYWN0dXJlPyAKCiMjIDNBOiBjYWxjdWxhdGluZyB0aGUgY29uZGl0aW9uYWwgcHJvYmFiaWxpdGllcyBvZiBmcmFjdHVyZSBmb3IgZWFjaCBjb25kaXRpb246IApgYGB7cn0KCiMjIElmIGZyYWN0dXJlZCB0aGUgZmlyc3QgdGltZSwgd2hhdCdzIHRoZSAlIG9mIGZyYWN0dXJpbmcgdGhlIHNlY29uZCB0aW1lPyBsb29rIGF0IDEgYW5kIEFwIGNvbWJpbmF0aW9uIGZvciAlIGluIHNlY29uZCB0aW1lOiAKCiMjIENvbXBhcmUgYm90aCB0cmVhdG1lbnQgYW5kIGNvbnRyb2wgd2l0aCBiYXNlbGluZSBhcyB0aGVvcmV0aWNhbCBkaXN0cmlidXRpb246IAoKIyMgQ29uZGl0aW9uYWwgcHJvYmFiaWxpdHkgZm9yIG1hc2tlZDogCiMgb2YgZ3JvdXBzIHdobyBmcmFjdHVyZWQgMSBhbmQgMgp0cmVhdG1lbnRGcmFjdHVyZTEyIDwtIHN1bShpZmVsc2UodHJlYXRtZW50RnJhY3R1cmUxJGZyYWN0dXJlPT0iMSIgJiB0cmVhdG1lbnRGcmFjdHVyZTIkZnJhY3R1cmU9PSIxIiwxLDApKS9ucm93KHRyZWF0bWVudEZyYWN0dXJlKQojIG9mIGdyb3VwcyB3aG8gZnJhY3R1cmVkIG9ubHkgMQp0cmVhdG1lbnRGcmFjdHVyZU9ubHkxIDwtIHN1bShpZmVsc2UodHJlYXRtZW50RnJhY3R1cmUxJGZyYWN0dXJlPT0iMSIgJiB0cmVhdG1lbnRGcmFjdHVyZTIkZnJhY3R1cmU9PSIwIiwxLDApKS9ucm93KHRyZWF0bWVudEZyYWN0dXJlKSAKIyBvZiBncm91cHMgd2hvIGZyYWN0dXJlZCBvbmx5IDIKdHJlYXRtZW50RnJhY3R1cmVPbmx5MiA8LSBzdW0oaWZlbHNlKHRyZWF0bWVudEZyYWN0dXJlMSRmcmFjdHVyZT09IjAiICYgdHJlYXRtZW50RnJhY3R1cmUyJGZyYWN0dXJlPT0iMSIsMSwwKSkvbnJvdyh0cmVhdG1lbnRGcmFjdHVyZSkKIyBvZiBncm91cHMgd2hvIGZyYWN0dXJlZCBuZXZlciAgICAgICAgCnRyZWF0bWVudEZyYWN0dXJlTmV2ZXIgPC0gc3VtKGlmZWxzZSh0cmVhdG1lbnRGcmFjdHVyZTEkZnJhY3R1cmU9PSIwIiAmIHRyZWF0bWVudEZyYWN0dXJlMiRmcmFjdHVyZT09IjAiLDEsMCkpL25yb3codHJlYXRtZW50RnJhY3R1cmUpCmNvbmRpdGlvbmFsUHJvYlRyZWF0bWVudCA8LSBtYXRyaXgoYyh0cmVhdG1lbnRGcmFjdHVyZTEyLCB0cmVhdG1lbnRGcmFjdHVyZU9ubHkxLCB0cmVhdG1lbnRGcmFjdHVyZU9ubHkyLCB0cmVhdG1lbnRGcmFjdHVyZU5ldmVyKSxuY29sPTIsYnlyb3c9VFJVRSkKY29sbmFtZXMoY29uZGl0aW9uYWxQcm9iVHJlYXRtZW50KSA8LSBjKCJBcCBmcmFjIiwiQXAgbm8gZnJhYyIpIApyb3duYW1lcyhjb25kaXRpb25hbFByb2JUcmVhdG1lbnQpIDwtIGMoIkEgZnJhYyIsIkEgbm8gZnJhYyIpCmNvbmRpdGlvbmFsUHJvYlRyZWF0bWVudCA8LSBhcy50YWJsZShjb25kaXRpb25hbFByb2JUcmVhdG1lbnQpCmNvbmRpdGlvbmFsUHJvYlRyZWF0bWVudAoKIyMgQ29uZGl0aW9uYWwgcHJvYWJpbGl0eSBmb3IgdW5tYXNrZWQ6IAojIG9mIGdyb3VwcyB3aG8gZnJhY3R1cmVkIDEgYW5kIDIKY29udHJvbEZyYWN0dXJlMTIgPC0gc3VtKGlmZWxzZShjb250cm9sRnJhY3R1cmUxJGZyYWN0dXJlPT0iMSIgJiBjb250cm9sRnJhY3R1cmUyJGZyYWN0dXJlPT0iMSIsMSwwKSkvbnJvdyhjb250cm9sRnJhY3R1cmUpCiMgb2YgZ3JvdXBzIHdobyBmcmFjdHVyZWQgb25seSAxCmNvbnRyb2xGcmFjdHVyZU9ubHkxIDwtIHN1bShpZmVsc2UoY29udHJvbEZyYWN0dXJlMSRmcmFjdHVyZT09IjEiICYgY29udHJvbEZyYWN0dXJlMiRmcmFjdHVyZT09IjAiLDEsMCkpL25yb3coY29udHJvbEZyYWN0dXJlKSAKIyBvZiBncm91cHMgd2hvIGZyYWN0dXJlZCBvbmx5IDIKY29udHJvbEZyYWN0dXJlT25seTIgPC0gc3VtKGlmZWxzZShjb250cm9sRnJhY3R1cmUxJGZyYWN0dXJlPT0iMCIgJiBjb250cm9sRnJhY3R1cmUyJGZyYWN0dXJlPT0iMSIsMSwwKSkvbnJvdyhjb250cm9sRnJhY3R1cmUpCiMgb2YgZ3JvdXBzIHdobyBmcmFjdHVyZWQgbmV2ZXIgICAgICAgIApjb250cm9sRnJhY3R1cmVOZXZlciA8LSBzdW0oaWZlbHNlKGNvbnRyb2xGcmFjdHVyZTEkZnJhY3R1cmU9PSIwIiAmIGNvbnRyb2xGcmFjdHVyZTIkZnJhY3R1cmU9PSIwIiwxLDApKS9ucm93KGNvbnRyb2xGcmFjdHVyZSkKY29uZGl0aW9uYWxQcm9iQ29udHJvbCA8LSBtYXRyaXgoYyhjb250cm9sRnJhY3R1cmUxMiwgY29udHJvbEZyYWN0dXJlT25seTEsIGNvbnRyb2xGcmFjdHVyZU9ubHkyLCBjb250cm9sRnJhY3R1cmVOZXZlciksbmNvbD0yLGJ5cm93PVRSVUUpCmNvbG5hbWVzKGNvbmRpdGlvbmFsUHJvYkNvbnRyb2wpIDwtIGMoIkFwIGZyYWMiLCJBcCBubyBmcmFjIikgCnJvd25hbWVzKGNvbmRpdGlvbmFsUHJvYlRyZWF0bWVudCkgPC0gYygiQSBmcmFjIiwiQSBubyBmcmFjIikKY29uZGl0aW9uYWxQcm9iQ29udHJvbCA8LSBhcy50YWJsZShjb25kaXRpb25hbFByb2JDb250cm9sKQpjb25kaXRpb25hbFByb2JDb250cm9sCmBgYAoKIyMgM0I6IE5vdyBpbnZlc3RpZ2F0aW5nIHRoZSBiaWcgcmVzdWx0OiBzd2l0Y2ggJTogd2hhdCdzIHRoZSAlIG9mIHBhaXJzIGZsaXBwaW5nIHRoZWlyIGRlY2lzaW9ucz8KCmBgYHtyfQojIyBDb252ZXJ0IGZvcm1hdCBiZWZvcmUgbWVyZ2U6ICp0aGlzIGNhbiBiZSBzaW1wbGlmaWVkKjogCgp0cmVhdG1lbnRGcmFjdHVyZTIkZnJhY3R1cmUgPC0gYXMubnVtZXJpYyh0cmVhdG1lbnRGcmFjdHVyZTIkZnJhY3R1cmUpIAp0cmVhdG1lbnRGcmFjdHVyZTEkZnJhY3R1cmUgPC0gYXMubnVtZXJpYyh0cmVhdG1lbnRGcmFjdHVyZTEkZnJhY3R1cmUpIAp0cmVhdG1lbnRGcmFjdHVyZSRhYnNGcmFjdHVyZSA8LSBhYnModHJlYXRtZW50RnJhY3R1cmUyJGZyYWN0dXJlLXRyZWF0bWVudEZyYWN0dXJlMSRmcmFjdHVyZSkKCmNvbnRyb2xGcmFjdHVyZTEkZnJhY3R1cmUgPC0gYXMubnVtZXJpYyhjb250cm9sRnJhY3R1cmUxJGZyYWN0dXJlKQpjb250cm9sRnJhY3R1cmUyJGZyYWN0dXJlIDwtIGFzLm51bWVyaWMoY29udHJvbEZyYWN0dXJlMiRmcmFjdHVyZSkKY29udHJvbEZyYWN0dXJlJGFic0ZyYWN0dXJlIDwtIGFicyhjb250cm9sRnJhY3R1cmUyJGZyYWN0dXJlLWNvbnRyb2xGcmFjdHVyZTEkZnJhY3R1cmUpCgojIGJhc2VsaW5lRnJhY3R1cmUkZnJhY3R1cmUxIDwtIGFzLm51bWVyaWMoYmFzZWxpbmVGcmFjdHVyZSRmcmFjdHVyZTEpIAojIGJhc2VsaW5lRnJhY3R1cmUkZnJhY3R1cmUyIDwtIGFzLm51bWVyaWMoYmFzZWxpbmVGcmFjdHVyZSRmcmFjdHVyZTIpIAojIGJhc2VsaW5lRnJhY3R1cmUkYWJzRnJhY3R1cmUgPC0gYWJzKGJhc2VsaW5lRnJhY3R1cmUkZnJhY3R1cmUxLWJhc2VsaW5lRnJhY3R1cmUkZnJhY3R1cmUyKQoKIyMgUmVzdWx0cyBoZXJlIHNlZW0gZmlzaHk/IFRyaXBsZSBjaGVjayBteSBjb2RlIGZvciBhYnMvc3VtPyAKCnRyZWF0bWVudEZyYWN0dXJlQWJzU3VtIDwtIHN1bSh0cmVhdG1lbnRGcmFjdHVyZSRhYnNGcmFjdHVyZSkgCnByaW50KHRyZWF0bWVudEZyYWN0dXJlQWJzU3VtKQpjb250cm9sRnJhY3R1cmVBYnNTdW0gPC0gc3VtKGNvbnRyb2xGcmFjdHVyZSRhYnNGcmFjdHVyZSkKcHJpbnQoY29udHJvbEZyYWN0dXJlQWJzU3VtKQojIyBiYXNlbGluZUZyYWN0dXJlQWJzU3VtIDwtIHN1bShiYXNlbGluZUZyYWN0dXJlJGFic0ZyYWN0dXJlKSAKCiMjIERvbid0IHdlIHdhbnQgYSBwcm9wb3J0aW9uIHRlc3QgaGVyZSBiZWZvcmUgYWRkaW5nIC8gdHJ5aW5nIGNoaS1zcXVhcmVkPyAKCnRyZWF0bWVudEFic0NoYW5nZT1jKCkgCmNvbnRyb2xBYnNDaGFuZ2U9YygpCgojIyBVc2luZyBiYXNlbGluZSBhcyB0aGVvcmV0aWNhbCBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb24gCiMjIFRyZWF0bWVudDogCmNoaXNxLnRlc3QodHJlYXRtZW50QWJzQ2hhbmdlLHA9YmFzZWxpbmVBYnNDaGFuZ2UpCgojIyBDb250cm9sOgpjaGlzcS50ZXN0KGNvbnRyb2xBYnNDaGFuZ2UscD1iYXNlbGluZUFic0NoYW5nZSkKYGBgCgojIyBWaXN1YWxpemluZyBjaGFuZ2U6IAoKYGBge3J9CiMjIFZpc3VhbGl6ZSBkaWZmZXJlbmNlczogCm5vcm1hbGl6ZWRUcmVhdG1lbnRDaGFuZ2UgPC0gdHJlYXRtZW50RnJhY3R1cmVBYnNTdW0vbnJvdyh0cmVhdG1lbnRGcmFjdHVyZSkKbm9ybWFsaXplZENvbnRyb2xDaGFuZ2UgPC0gY29udHJvbEZyYWN0dXJlQWJzU3VtL25yb3coY29udHJvbEZyYWN0dXJlKQoKZGF0IDwtIGRhdGEuZnJhbWUoY2hhbmdlc1BlckNvbmRpdGlvbj0gZmFjdG9yKGMoIk5vcm1hbGl6ZWQgcGVyY2VudGFnZSBvZiBhYnNvbHV0ZSBmcmFjdHVyZSBjaGFuZ2UgaW4gbWFza2VkID49LjUwIiwiTm9ybWFsaXplZCBwZXJjZW50YWdlIG9mIGFic29sdXRlIGZyYWN0dXJlIGNoYW5nZSBpbiB1bm1hc2tlZCA+PS41MCIpLCBsZXZlbHM9YygiTm9ybWFsaXplZCBwZXJjZW50YWdlIG9mIGFic29sdXRlIGZyYWN0dXJlIGNoYW5nZSBpbiBtYXNrZWQgPj0uNTAiLCJOb3JtYWxpemVkIHBlcmNlbnRhZ2Ugb2YgYWJzb2x1dGUgZnJhY3R1cmUgY2hhbmdlIGluIHVubWFza2VkID49LjUwIikpLAogICAgICAgICAgICAgICAgICBmcmFjdHVyZVZhbHVlU3dpdGNoID0gYyhub3JtYWxpemVkVHJlYXRtZW50Q2hhbmdlLCBub3JtYWxpemVkQ29udHJvbENoYW5nZSkpCgpwIDwtIGdncGxvdChkYXRhPWRhdCwgYWVzKHg9Y2hhbmdlc1BlckNvbmRpdGlvbiwgeT1mcmFjdHVyZVZhbHVlU3dpdGNoKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikKcCA8LSBnZ3Bsb3RseShwKQpwCmBgYAoKCgoKCgoKCg==